package com.googlecode.archimedes.filegen.generator.freemarker;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.googlecode.archimedes.filegen.controller.GenerationException;
import com.googlecode.archimedes.filegen.generator.AbstractGenerator;
import com.googlecode.archimedes.filegen.model.AbstractType;
import com.googlecode.archimedes.filegen.model.Abstractable;
import com.googlecode.archimedes.filegen.model.Application;
import com.googlecode.archimedes.filegen.model.Asset;
import com.googlecode.archimedes.filegen.model.Enumeration;
import com.googlecode.archimedes.util.ModelUtil;

import freemarker.template.SimpleHash;

/**
 * <p>
 * Right now i'm making this look exactly liek the Legacy example of VelocityApplicatonGenerator
 * And later I'll customize and clean it up.
 * This Class generates a collection of files from an applicaiton model and a collection of templates.  
 * It uses a Generator to write each file individually to avoid the messiness of looking ofr files and 
 * cleaning up the open OutputStream, etc.... 
 * </p>
 * <p>Created: Jan 13, 2005</p>
 * @author John Lema 
 * @version $Id: FreeMarkerApplicationGenerator.java 2023 2006-02-18 01:16:42 +0000 (Sat, 18 Feb 2006) erik $
 */
public class FreeMarkerApplicationGenerator extends AbstractGenerator {

    private Log log = LogFactory.getLog(this.getClass().getName());

    //-------------- Main Methods ---------------------------------------------------------------
    /**
     * This is an exact copy of the same method in VelocityApplicaitonGenerator
     * It should be moved into a common class.
     * 
     * Loop through the Collection of assets and attempt to generate
     * based on the Template we have been passed.
     * 
     * @see com.tps.filegen.generator.AbstractGenerator#generate()
     */
    public void generate() throws GenerationException {
        for (Asset asset : this.getAssets()) {

            //check to see if the template we are generating matches any assets
            if (this.getTemplate().getAllowedAssetClass().isInstance(asset)) {

                //check and see if our asset is abstractable and that the template
                //allows this
                if (asset instanceof Abstractable) {
                    Abstractable abstractable = (Abstractable) asset;
                    if (abstractable.isAbstract() && !getTemplate().isAbstractAllowed()) {
                        log.info("The Asset [" + asset + "] is abstract and the template [" + getTemplate().getTemplateName() + "] does not allow abstract assets.");
                        continue;
                    }
                }

                //generate our code depending on what kind of asset we are working with
                if (asset instanceof AbstractType) {
                    generateEntity((AbstractType) asset);
                } else if (asset instanceof Application) {
                    generateApplication((Application) asset);
                } else if (asset instanceof Enumeration) {
                    generateEnumeration((Enumeration) asset);
                }
            }
        }
    }

    /**
     * This method creates all the files necessary for an Entity.  
     * Compare to the same method name in VelocityApplicationGenerator
     * @see com.tps.filegen.generator.velocity.VelocityApplicationGenerator#generateEntity()
     */
    protected void generateEnumeration(Enumeration anEnum) throws GenerationException {

        //SimpleHash is FreeMarker specific
        SimpleHash dataModel = new SimpleHash();

        //Entity templates need an App and an Entity
        dataModel.put("app", findApp());
        dataModel.put("bo", anEnum);
        dataModel.put("util", new ModelUtil());
        dataModel.put("tf", getTemplate()); //not sure if this is needed any more

        FreeMarkerGenerator.generate(this, anEnum.getName(), this.getTemplate(), dataModel);
    }

    /**
     * This method creates all the files necessary for an Entity.  
     * Compare to the same method name in VelocityApplicationGenerator
     * @see com.tps.filegen.generator.velocity.VelocityApplicationGenerator#generateEntity()
     */
    protected void generateEntity(AbstractType asset) throws GenerationException {

        //SimpleHash is FreeMarker specific
        SimpleHash dataModel = new SimpleHash();

        //Entity templates need an App and an Entity
        dataModel.put("app", findApp());
        dataModel.put("bo", asset);
        dataModel.put("util", new ModelUtil());
        dataModel.put("tf", getTemplate()); //not sure if this is needed any more

        FreeMarkerGenerator.generate(this, asset.getEntityName(), this.getTemplate(), dataModel);
    }

    /**
     * This method creates all the files necessary for an Application.  
     * Compare to the same method name in VelocityApplicationGenerator
     * @see com.tps.filegen.generator.velocity.VelocityApplicationGenerator#generateApplication()
     */
    protected void generateApplication(Application app) throws GenerationException {

        SimpleHash dataModel = new SimpleHash();

        //SimpleHash is FreeMarker specific
        dataModel.put("app", app);

        //Entity templates need an App and an Entity
        dataModel.put("bos", app.getEntities());
        dataModel.put("util", new ModelUtil());
        dataModel.put("tf", getTemplate()); //not sure if this is needed any more
        FreeMarkerGenerator.generate(this, "", this.getTemplate(), dataModel);
    }

    //---------------------Utility Methods --------------------------------------------------------------

    protected Application findApp() throws GenerationException {
        for (Asset asset : getAssets()) {
            if (asset instanceof Application) { return (Application) asset; }
        }

        throw new GenerationException("Unable to find an Application object.");
    }
}
